package com.prs.crm.dao.flow.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.courser.ui.PaginationSupport;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;

import com.prs.crm.dao.flow.WorkFlowProcessDao;
import com.prs.crm.dao.impl.BaseDaoImpl;
import com.prs.crm.domain.FlowEntity;
import com.prs.crm.domain.flow.WorkFlowNode;
import com.prs.crm.domain.flow.WorkFlowProcess;
import com.prs.crm.domain.flow.WorkFlowProcessNode;
import com.prs.crm.domain.flow.WorkFlowTransition;
import com.prs.crm.domain.hr.Person;
import com.prs.crm.domain.stock.ProductStore;

public class WorFlowProcessDaoImpl extends BaseDaoImpl<WorkFlowProcess> implements WorkFlowProcessDao{
	

	
	public void saveProcessEntity(FlowEntity entity)
	{
		this.getHibernateTemplate().save(entity);
	}
	
	@SuppressWarnings("unchecked")
	public Collection<?> findFlowEntitys(final Class cls,final Person person,final Integer[] status)
	{
		return (Collection<?>)getHibernateTemplate().execute(   
			      new HibernateCallback() {   
					public Object doInHibernate(Session session) throws HibernateException {

			        	Criteria criteria =  session.createCriteria(cls);
			        	criteria.createAlias("process", "p").createAlias("p.processNodes", "pn");
			        	criteria.add(Restrictions.or(
			        				Restrictions.or(Restrictions.eq("pn.handler.principal", person), 
			        				Restrictions.eq("pn.handler.executors", person)),
			        				Restrictions.and(Restrictions.eq("pn.dept", person.getDept()), Restrictions.eq("pn.role", person.getRole()))
			        			));
			        	criteria.add(Restrictions.in("pn.flowstatus", status));
			        	
			        	return criteria.list();
			        }   
			      }   
			    ); 
	}
	
    @SuppressWarnings("unchecked")
	public FlowEntity findProcessEntity(final WorkFlowProcess process,final Class cls)
	{
		return (FlowEntity)getHibernateTemplate().execute(   
			      new HibernateCallback() {   
					public Object doInHibernate(Session session) throws HibernateException {   
					//	System.out.println("worflowProcessDaoImpl   "+cls.toString());
					//	System.out.println(process.getId());
			        	Criteria criteria =  session.createCriteria(cls);
			        	criteria.add(Restrictions.eq("process", process));	
			        	List<FlowEntity> result = criteria.list();
			        	/*if(result!=null){
			        		System.out.println("1"+result.get(0).getClass());
			        	}*/
			        	//System.out.println("Dao层里面的XXXX ="+result.size());
			        	if (result.size()>0){
			        	   
			        		return result.get(0);
			     }
			        	else{
			        		return null;
			        	}					}
			      }   
			    );  
	}

	@SuppressWarnings("unchecked")
	public Collection<WorkFlowProcessNode> getNodeByStatus(final WorkFlowProcess process,final Integer status)
	{
		return (Collection<WorkFlowProcessNode> )getHibernateTemplate().execute(   
			      new HibernateCallback() {   
			        public Object doInHibernate(Session session) throws HibernateException { 
			        //	System.out.println("worflowProcessDaoImpl    getNodeByStatus  "+process.getClass());
			        	Criteria criteria =  session.createCriteria(WorkFlowProcessNode.class,"f");
			        	criteria.createAlias("instanceNode", "i");
			        	criteria.add(Restrictions.eq("f.flowProcess", process)).add(Restrictions.eq("f.status", status));
			        	criteria.addOrder(Order.asc("i.sequence"));
			        	return criteria.list();
			        }   
			      }   
			    );  
	}
	@SuppressWarnings("unchecked")
	public Collection<WorkFlowProcessNode> getNodeByNodeType(final WorkFlowProcess process,final Integer type)
	{
		return (Collection<WorkFlowProcessNode> )getHibernateTemplate().execute(   
			      new HibernateCallback() {   
			        public Object doInHibernate(Session session) throws HibernateException {   
			        	Criteria criteria =  session.createCriteria(WorkFlowProcessNode.class,"p");
			        	criteria.add(Restrictions.eq("flowProcess", process)).
			        		createAlias("p.instanceNode", "pi").createAlias("pi.flownode", "node")
			        		.add(Restrictions.eq("node.type", type));
			        	return criteria.list();
			        }   
			      }   
			    );  
	}
	
	@SuppressWarnings("unchecked")
	public 	Collection<WorkFlowProcessNode> getNextProcessNodes(final WorkFlowProcessNode node)
	{
		return (Collection<WorkFlowProcessNode> )getHibernateTemplate().execute(   
			      new HibernateCallback() {   
			        public Object doInHibernate(Session session) throws HibernateException {  
			        	
			        	Criteria criteria = session.createCriteria(WorkFlowTransition.class);
			        	if (node!=null)
			        		criteria.add(Restrictions.eq("startnode", node.getInstanceNode().getFlownode()));
			        	else
			        		criteria.add(Restrictions.isNull("startnode"));
			        	List<WorkFlowNode> nodes = new ArrayList<WorkFlowNode>();
			        	for (WorkFlowTransition trans : (Collection<WorkFlowTransition>)criteria.list())
			        	{
			        		nodes.add(trans.getEndnode());
			        	}
			        	if (nodes.size()>0)
			        	{
			        		
				        	Criteria criteria1 =  session.createCriteria(WorkFlowProcessNode.class,"p").createAlias("instanceNode", "pi");
				        	criteria1.add(Restrictions.eq("flowProcess", node.getFlowProcess())).add(Restrictions.in("pi.flownode", nodes));
				        		//.setFetchMode("instanceNode", FetchMode.JOIN);
				        	List<WorkFlowProcessNode> result =  criteria1.list();
				       
				        	return result;
			        	}
			        	else
			        	{
			        		return null;
			        	}
			        }   
			      }   
			    );  
	}
	
	public void saveProcessNode(WorkFlowProcessNode node)
	{
		this.getHibernateTemplate().save(node);
	}

	@SuppressWarnings("unchecked")
	public int updateProcessNode(final WorkFlowProcess process,final Integer status,final Integer result)
	{
		return  (Integer)getHibernateTemplate().execute(   
			      new HibernateCallback() {   
				   public Object doInHibernate(Session session) throws HibernateException {   
					   Query query = session.createQuery("update WorkFlowProcessNode set result=?,status=? where flowProcess=?");
					   query.setParameter(0, result).setParameter(1, status).setParameter(2, process);
					   return query.executeUpdate();
		        }   
		      }   
		); 
	}
	@SuppressWarnings("unchecked")
	public int countProcessNodes(final WorkFlowProcess process,final Integer status,final Integer result)
	{
		return (Integer)getHibernateTemplate().execute(   
			      new HibernateCallback() {   
			        public Object doInHibernate(Session session) throws HibernateException {   
			        	Criteria criteria =  session.createCriteria(WorkFlowProcessNode.class);
			        	criteria.add(Restrictions.eq("process", process));
			        	if (status!=null)
			        	{
			        		criteria.add(Restrictions.eq("status", status));
			        	}
			        	if (result!=null)
			        	{
			        		criteria.add(Restrictions.eq("result", result));
			        	}
			        	criteria.setProjection(Projections.count("id"));
			        	return criteria.list();
			        }   
			      }   
			    );  
	}
	
	@SuppressWarnings("unchecked")
	public PaginationSupport pageQueryFlowNode(final Class<?> cls ,final  PaginationSupport page,final Person person,final Integer[] status)
	{
		return (PaginationSupport)getHibernateTemplate().execute(   
			      new HibernateCallback() {   
			        public Object doInHibernate(Session session) throws HibernateException {   
			        	String statusCondition = null;
			        	for (Integer  state : status)
			        	{
			        		statusCondition = (statusCondition==null)?state.toString():statusCondition+","+state.toString();
			        	}
			        	String countql = "select count(distinct p.id) from WorkFlowProcessNode p left join p.handler.executors e where " +
	        			" ((p.handler.dept=? and p.handler.role=?) or p.handler.principal=? or e.id=?) and (p.status in ("+statusCondition+"))" +
	        					" and p.flowProcess in (select distinct wp from "+cls.getSimpleName()+" cl inner join cl.process wp)";
			        	String hql = "select distinct p from WorkFlowProcessNode p left join p.handler.executors e where " +
			        			" (( p.handler.dept=? and p.handler.role=? ) or p.handler.principal=? or e.id=?) and (p.status in ("+statusCondition+"))"+
			        			" and p.flowProcess in (select distinct wp from "+cls.getSimpleName()+" cl inner join cl.process wp)";
			        
		                hql+=" order by p.id";
		              
			        	Query countQuery =session.createQuery(countql);
			        	Query query = session.createQuery(hql);
			        	
			        	
			        	countQuery.setParameter(0, person.getDept());
			        	countQuery.setParameter(1, person.getRole());
			        	countQuery.setParameter(2, person);
			        	countQuery.setParameter(3, person.getId());
			        	query.setParameter(0, person.getDept());
			        	query.setParameter(1, person.getRole());
			        	query.setParameter(2, person);
			        	query.setParameter(3, person.getId());
			        	List<?> items = query.setFirstResult(page.getStartIndex()).setMaxResults(page.getPageSize()).list();
			        	int totalCount = Integer.parseInt(countQuery.uniqueResult().toString());
			            PaginationSupport ps = new PaginationSupport();
		                ps.setPageSize(page.getPageSize());
		                ps.setItems(items);
		                ps.setTotalCount(totalCount);
		                ps.setStartIndex(page.getStartIndex());
		                int totalPage =totalCount / ps.getPageSize();
		                if(totalPage * ps.getPageSize() <totalCount)
		                    totalPage++;
		                ps.setTotalPage(totalPage);
		                ps.setCurrentPage(page.getCurrentPage());
		                ps.setSort(page.getSort());
		                ps.setDirection(page.getDirection());

			        	return ps;
			        }   
			      }   
			    );  
	}

	@Override
	public WorkFlowProcess getWorkFlowProcess(Serializable id) {
		
		return this.getHibernateTemplate().get(WorkFlowProcess.class, id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<WorkFlowProcessNode> getWorkFlowProcessNode(final WorkFlowProcess flowProcess) {
		return (List<WorkFlowProcessNode> )getHibernateTemplate().execute(   
			      new HibernateCallback() {   
			        public Object doInHibernate(Session session) throws HibernateException {   
			        	Criteria criteria =  session.createCriteria(WorkFlowProcessNode.class);
			        	criteria.add(Restrictions.eq("flowProcess", flowProcess));
			        	
			        	List<WorkFlowProcessNode> result = criteria.list();
			        
			        	if (result.size()>0){
			        		
			        		
			        		return result;
			        	
			        	}
			        	else{
			        		return null;
			        	}
			        }   
			      }   
			    );  
	}

	@Override
	public void saveOrUpdate(WorkFlowProcess flowProcess) {
		
		this.getHibernateTemplate().saveOrUpdate(flowProcess);
		
	}

	@Override
	public void saveOrUpdateWorkFlowProcessNode(
			WorkFlowProcessNode workFlowProcessNode) {
		this.getHibernateTemplate().saveOrUpdate(workFlowProcessNode);
		
	}
	
}
